package org.aphelie.torg.ruler.internal.ui.editor.character;

import org.aphelie.torg.ruler.core.IBaseModel;
import org.aphelie.torg.ruler.core.IModelChangeProvider;
import org.aphelie.torg.ruler.core.IModelChangedEvent;
import org.aphelie.torg.ruler.core.character.CharacterRegistry;
import org.aphelie.torg.ruler.core.character.ICharacterBase;
import org.aphelie.torg.ruler.core.character.ICharacterModelBase;
import org.aphelie.torg.ruler.core.character.ICharacterSketch;
import org.aphelie.torg.ruler.internal.ui.TGRPlugin;
import org.aphelie.torg.ruler.internal.ui.TGRUIMessages;
import org.aphelie.torg.ruler.internal.ui.editor.FormEntryAdapter;
import org.aphelie.torg.ruler.internal.ui.editor.FormLayoutFactory;
import org.aphelie.torg.ruler.internal.ui.editor.IContextPart;
import org.aphelie.torg.ruler.internal.ui.editor.TGRFormPage;
import org.aphelie.torg.ruler.internal.ui.editor.TGRSection;
import org.aphelie.torg.ruler.internal.ui.editor.character.validation.ControlValidationUtility;
import org.aphelie.torg.ruler.internal.ui.editor.character.validation.TextValidator;
import org.aphelie.torg.ruler.internal.ui.parts.FormEntry;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;

public abstract class GeneralInfoSection extends TGRSection {
	
	private static String PLATFORM_FILTER = "Eclipse-PlatformFilter"; //$NON-NLS-1$

	private FormEntry fIdEntry;
	private FormEntry fNameEntry;
	private FormEntry fPlayerEntry;
	private FormEntry fChronicleEntry;
	private FormEntry fStrainEntry;
	
	
	private FormEntry fVersionEntry;
	
	private FormEntry fProviderEntry;
	private FormEntry fPlatformFilterEntry;

	private TextValidator fIdEntryValidator;
	private TextValidator fNameEntryValidator;
	private TextValidator fPlayerEntryValidator;
	private TextValidator fChronicleEntryValidator;
	private TextValidator fStrainEntryValidator;
	

	private TextValidator fVersionEntryValidator;

	private TextValidator fProviderEntryValidator;

	private TextValidator fPlatformEntryValidator;

	private ICharacterModelBase fModel;

	protected Button fSingleton;

	public GeneralInfoSection(TGRFormPage page, Composite parent) {
		super(page, parent, Section.DESCRIPTION);
		createClient(getSection(), page.getEditor().getToolkit());
	}
	
	protected void createClient(Section section, FormToolkit toolkit) {
		section.setText(TGRUIMessages.CharacterEditor_GeneralInfoSection_title);
		section.setLayout(FormLayoutFactory.createClearTableWrapLayout(false, 1));
		TableWrapData data = new TableWrapData(TableWrapData.FILL_GRAB);
		section.setLayoutData(data);
		
		section.setDescription(getSectionDescription());
		Composite client = toolkit.createComposite(section);
		client.setLayout(FormLayoutFactory.createSectionClientTableWrapLayout(false, 3));
		section.setClient(client);
		
		IActionBars actionBars = getPage().getTGREditor().getEditorSite().getActionBars();
		createIDEntry(client, toolkit, actionBars);
		createVersionEntry(client, toolkit, actionBars);
		createNameEntry(client, toolkit, actionBars);
		createPlayerEntry(client, toolkit, actionBars);
		createChronicleEntry(client, toolkit, actionBars);
		createStrainEntry(client, toolkit, actionBars);
			
		
		createProviderEntry(client, toolkit, actionBars);
		//if (isBundle() && ((ManifestEditor) getPage().getEditor()).isEquinox())
			//createPlatformFilterEntry(client, toolkit, actionBars);
		createSpecificControls(client, toolkit, actionBars);
		toolkit.paintBordersFor(client);

		addListeners();
	}
	
	protected abstract String getSectionDescription();
	
	protected abstract void createSpecificControls(Composite parent, FormToolkit toolkit, IActionBars actionBars);

	protected ICharacterBase getCharacterBase() {
		IBaseModel model = getPage().getTGREditor().getAggregateModel();
		return ((ICharacterModelBase) model).getCharacterBase();
	}
	
    protected ICharacterModelBase getModelBase() {
        if (fModel == null) {
            fModel = CharacterRegistry.findModel(getProject());
        }
        return fModel;
    }

    private void createIDEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
        fIdEntry = new FormEntry(client, toolkit, TGRUIMessages.CharacterEditor_GeneralInfoSection_id, null, false);

        fIdEntry.setFormEntryListener(new FormEntryAdapter((IContextPart) this, actionBars) {

            public void textValueChanged(FormEntry entry) {
                try {
                    getCharacterBase().setId(entry.getValue());
                } catch (CoreException e) {
                    TGRPlugin.logException(e);
                }
            }
        });

        fIdEntry.setEditable(true); //TODO(isEditable());
        fIdEntryValidator = new TextValidator(getManagedForm(), fIdEntry.getText(), getProject(), true) {

            protected boolean validateControl() {
                return validateIdEntry();
            }
        };
    }

    private boolean validateIdEntry() {
        // Value must be specified
        return ControlValidationUtility.validateRequiredField(fIdEntry.getText().getText(), fIdEntryValidator,
                IMessageProvider.ERROR);
    }
	

    /**
     * Name entry creation
     */
    private void createNameEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
        fNameEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_name, null, false);
        fNameEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {

            public void textValueChanged(FormEntry entry) {
                try {
                    getCharacterBase().setName(entry.getValue());
                } catch (CoreException e) {
                    TGRPlugin.logException(e);
                }
            }
        });
        fNameEntry.setEditable(isEditable());

        fNameEntryValidator = new TextValidator(getManagedForm(), fNameEntry.getText(), getProject(), true) {

            protected boolean validateControl() {
                return validateNameEntry();
            }
        };
    }

    private boolean validateNameEntry() {
        return ControlValidationUtility.validateTranslatableField(fNameEntry.getText().getText(), fNameEntryValidator, getModelBase(), getProject());
    }
	 
    /**
     * Player entry creation
     */
    private void createPlayerEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
        fPlayerEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_player, null, false);
        fPlayerEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {

            public void textValueChanged(FormEntry entry) {
                try {
                    ICharacterBase cb = getCharacterBase();
                    ICharacterSketch rep = cb.getSketch();
                    getCharacterBase().setPlayer(entry.getValue());
                } catch (CoreException e) {
                    TGRPlugin.logException(e);
                }
            }
        });
        fPlayerEntry.setEditable(isEditable());

        fPlayerEntryValidator = new TextValidator(getManagedForm(), fPlayerEntry.getText(), getProject(), true) {

            protected boolean validateControl() {
                return validatePlayerEntry();
            }
        };
    }

    private boolean validatePlayerEntry() {
        return ControlValidationUtility.validateTranslatableField(fPlayerEntry.getText().getText(), fPlayerEntryValidator, getModelBase(), getProject());
    }
    
    /**
     * Chronicle entry creation
     */
    private void createChronicleEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
        fChronicleEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_chronicle, null, false);
        fChronicleEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {

            public void textValueChanged(FormEntry entry) {
                try {
                    getCharacterBase().setChronicle(entry.getValue());
                } catch (CoreException e) {
                    TGRPlugin.logException(e);
                }
            }
        });
        fChronicleEntry.setEditable(isEditable());

        fChronicleEntryValidator = new TextValidator(getManagedForm(), fChronicleEntry.getText(), getProject(), true) {

            protected boolean validateControl() {
                return validateChronicleEntry();
            }
        };
    }

    private boolean validateChronicleEntry() {
        return ControlValidationUtility.validateTranslatableField(fChronicleEntry.getText().getText(), fChronicleEntryValidator, getModelBase(), getProject());
    }
    
    /**
     * Strain entry creation
     */
    private void createStrainEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
        fStrainEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_strain, null, false);
        fStrainEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {

            public void textValueChanged(FormEntry entry) {
                try {
                    getCharacterBase().setStrain(entry.getValue());
                } catch (CoreException e) {
                    TGRPlugin.logException(e);
                }
            }
        });
        fStrainEntry.setEditable(isEditable());

        fStrainEntryValidator = new TextValidator(getManagedForm(), fStrainEntry.getText(), getProject(), true) {

            protected boolean validateControl() {
                return validateStrainEntry();
            }
        };
    }

    private boolean validateStrainEntry() {
        return ControlValidationUtility.validateTranslatableField(fStrainEntry.getText().getText(), fStrainEntryValidator, getModelBase(), getProject());
    }
	   
	   
	   
	   
	
	private void createVersionEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
		fVersionEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_version, null, false);
		fVersionEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {
			public void textValueChanged(FormEntry entry) {
				try {
					getCharacterBase().setVersion(entry.getValue());
				} catch (CoreException e) {
					TGRPlugin.logException(e);
				}
			}
		});
		fVersionEntry.setEditable(isEditable());
		// Create validator
		fVersionEntryValidator = new TextValidator(getManagedForm(), fVersionEntry.getText(), getProject(), true) {
			protected boolean validateControl() {
				return validateVersionEntry();
			}
		};
	}

	private boolean validateVersionEntry() {
		// Value must be specified
		if (ControlValidationUtility.validateRequiredField(fVersionEntry.getText().getText(), fVersionEntryValidator, IMessageProvider.ERROR) == false) {
			return false;
		}
		// Value must be a valid version
		return ControlValidationUtility.validateVersionField(fVersionEntry.getText().getText(), fVersionEntryValidator);
	}


	

	
	private void createProviderEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
		fProviderEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_provider, null, false);
		fProviderEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {
			public void textValueChanged(FormEntry entry) {
				try {
					getCharacterBase().setProviderName(entry.getValue());
				} catch (CoreException e) {
					TGRPlugin.logException(e);
				}
			}
		});
		fProviderEntry.setEditable(isEditable());
		// Create validator
		fProviderEntryValidator = new TextValidator(getManagedForm(), fProviderEntry.getText(), getProject(), true) {
			protected boolean validateControl() {
				return validateProviderEntry();
			}
		};
	}

	private boolean validateProviderEntry() {
		// No validation required for an optional field
		if (fProviderEntry.getText().getText().length() == 0) {
			return true;
		}
		// Value must be externalized
		return ControlValidationUtility.validateTranslatableField(fProviderEntry.getText().getText(), fProviderEntryValidator, getModelBase(), getProject());
	}

	private void createPlatformFilterEntry(Composite client, FormToolkit toolkit, IActionBars actionBars) {
		fPlatformFilterEntry = new FormEntry(client, toolkit, TGRUIMessages.GeneralInfoSection_platformFilter, null, false);
		/** TODO
		fPlatformFilterEntry.setFormEntryListener(new FormEntryAdapter(this, actionBars) {
			public void textValueChanged(FormEntry entry) {
				getBundle().setHeader(PLATFORM_FILTER, fPlatformFilterEntry.getValue());
			}
		});
		*/
		fPlatformFilterEntry.setEditable(isEditable());
		// Create validator
		fPlatformEntryValidator = new TextValidator(getManagedForm(), fPlatformFilterEntry.getText(), getProject(), true) {
			protected boolean validateControl() {
				return validatePlatformEntry();
			}
		};
	}

	private boolean validatePlatformEntry() {
		// No validation required for an optional field
		if (fPlatformFilterEntry.getText().getText().length() == 0) {
			return true;
		}
		// Value must match the current environment and contain valid syntax
		return ControlValidationUtility.validatePlatformFilterField(fPlatformFilterEntry.getText().getText(), fPlatformEntryValidator);
	}
	
	public void commit(boolean onSave) {
		fIdEntry.commit();
		fVersionEntry.commit();
		fNameEntry.commit();
		fPlayerEntry.commit();
		fChronicleEntry.commit();
		fStrainEntry.commit();
		fProviderEntry.commit();
		if (fPlatformFilterEntry != null)
			fPlatformFilterEntry.commit();
		super.commit(onSave);
	}
	
	
	
	public void modelChanged(IModelChangedEvent e) {
		if (e.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
			markStale();
			return;
		}
		refresh();
		if (e.getChangeType() == IModelChangedEvent.CHANGE) {
			Object obj = e.getChangedObjects()[0];
			if (obj instanceof ICharacterBase) {
				String property = e.getChangedProperty();
				if (property != null && property.equals(getPage().getTGREditor().getTitleProperty()))
					getPage().getTGREditor().updateTitle();;
			}
		}

	}
		
	
	public void refresh() {
		ICharacterModelBase model = (ICharacterModelBase) getPage().getTGREditor().getContextManager().getAggregateModel();
		ICharacterBase characterBase = model.getCharacterBase();
		fIdEntry.setValue(characterBase.getId(), true);
		fNameEntry.setValue(characterBase.getName(), true);
		fPlayerEntry.setValue(characterBase.getPlayer(), true);
		fChronicleEntry.setValue(characterBase.getChronicle(), true);
		fStrainEntry.setValue(characterBase.getStrain(), true);
		fVersionEntry.setValue(characterBase.getVersion(), true);
		fProviderEntry.setValue(characterBase.getProviderName(), true);
		/**
		if (fPlatformFilterEntry != null) {
			IBundle bundle = getBundle();
			if (bundle != null)
				fPlatformFilterEntry.setValue(bundle.getHeader(PLATFORM_FILTER), true);
		}*/
		getPage().getTGREditor().updateTitle();
		/**
		if (fSingleton != null) {
			IManifestHeader header = getSingletonHeader();
			fSingleton.setSelection(header instanceof BundleSymbolicNameHeader && ((BundleSymbolicNameHeader) header).isSingleton());
		}
		*/
		super.refresh();		
	}

	public void cancelEdit() {
		fIdEntry.cancelEdit();
		fNameEntry.cancelEdit();
		fVersionEntry.cancelEdit();
		fProviderEntry.cancelEdit();
		if (fPlatformFilterEntry != null)
			fPlatformFilterEntry.cancelEdit();
		super.cancelEdit();
	}

	public void dispose() {
		removeListeners();
		super.dispose();
	}

	protected void removeListeners() {
		IBaseModel model = getPage().getModel();
		if (model instanceof IModelChangeProvider)
			((IModelChangeProvider) model).removeModelChangedListener(this);
	}

	protected void addListeners() {
		IBaseModel model = getPage().getModel();
		if (model instanceof IModelChangeProvider)
			((IModelChangeProvider) model).addModelChangedListener(this);
	}

	public boolean canPaste(Clipboard clipboard) {
		Display d = getSection().getDisplay();
		return (d.getFocusControl() instanceof Text);
	}

	/** TODO
	IManifestHeader getSingletonHeader() {
		IBundle bundle = getBundle();
		if (bundle instanceof Bundle) {
			IManifestHeader header = bundle.getManifestHeader(Constants.BUNDLE_SYMBOLICNAME);
			return header;
		}
		return null;
	}
	*/

	protected void createSingleton(Composite parent, FormToolkit toolkit, IActionBars actionBars, String label) {
		fSingleton = toolkit.createButton(parent, label, SWT.CHECK);
		TableWrapData td = new TableWrapData();
		td.colspan = 3;
		fSingleton.setLayoutData(td);
		fSingleton.setEnabled(isEditable());
		fSingleton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				//IManifestHeader header = getSingletonHeader();
				//if (header instanceof BundleSymbolicNameHeader)
					//((BundleSymbolicNameHeader) header).setSingleton(fSingleton.getSelection());
			}
		});
	}

	
}
